#include "HUDManager.h"
#include "../nclgl\Window.h"


HUDManager* HUDManager::pInst = 0;

HUDManager::HUDManager(): Debug_Mode(false),Exit(false),GameTime(50.0f),Fullscreen(false) //Reset_HUD(false),Running(false),Paused(false)
{
	///set screen window to intial position to avoid annoying Hud positioning problems
	RECT rect;
	rect.left = 0;
	rect.top = 0;
	rect.right = 1280;
	rect.bottom = 800;
	deathDelay = true;

	ChangeDisplaySettings(0, 0);

	SetWindowLongPtr(Window::GetWindow().GetHandle(), GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
	AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
	MoveWindow(Window::GetWindow().GetHandle(), 0, 0, rect.right-rect.left, rect.bottom-rect.top, TRUE);
}

HUDManager::~HUDManager()
{
	//write high score to file
	WriteHighScore("High_Score.txt");

	//delete buttons
	for(vector<Button<HUDManager>*>::iterator it = PauseButtons.begin(); it != PauseButtons.end();it++)
	{
		delete (*it);
	}
	for (vector<Button<HUDManager>*>::iterator it = StartButtons.begin(); it != StartButtons.end(); it++)
	{
		delete (*it);
}
	for (vector<Button<HUDManager>*>::iterator it = GameOverButtons.begin(); it != GameOverButtons.end(); it++)
	{
		delete (*it);
	}
}

HUDManager* HUDManager::GetInstance()
{
	//If no instance exists create one then return it
	if(pInst == 0)
	{
		pInst = new HUDManager();
	}

	return pInst;
}

void HUDManager::Release()
{
	//if instance exists delete it
	if(pInst)
	{
		delete pInst;
	}
}

void HUDManager::Intialise()
{
	// --------------- Added by Monica ------------------------ //
	SinglePlayer = false;
	MultiPlayer = false;
	// ---------------------------------------------------------- //

	///Creates the buttons for start,pause and game over menus/////////////////////////////////
	float position = 300;
	/////////////Pause Buttons///////////////////////////////////////
	Button<HUDManager>* temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::SwitchToMain);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Main_ST.png",TEXTUREDIR"/Button Textures/Main_SE.png");
	PauseButtons.push_back(temp);
	position += 100;

	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::ToggleFullscreen);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Full_ST.png",TEXTUREDIR"/Button Textures/Full_SE.png");
	PauseButtons.push_back(temp);
	position += 100;

	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::ToggleReset_HUD);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Restart_ST.png",TEXTUREDIR"/Button Textures/Restart_SE.png");
	PauseButtons.push_back(temp);
	position += 100;

	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::SwitchToGame);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Resume_ST.png",TEXTUREDIR"/Button Textures/Resume_SE.png");
	PauseButtons.push_back(temp);
	position += 100;

	position = 300;
	/////////////Start Buttons///////////////////////////////////////
	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::ToggleExit);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Exit_ST.png",TEXTUREDIR"/Button Textures/Exit_SE.png");
	StartButtons.push_back(temp);
	position += 100;

	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::SetMultiPlayer);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Multi_ST.png",TEXTUREDIR"/Button Textures/Multi_SE.png");
	StartButtons.push_back(temp);
	position += 100;


	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::SetSinglePlayer);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Single_ST.png",TEXTUREDIR"/Button Textures/Single_SE.png");
	StartButtons.push_back(temp);
	position += 100;

	position = 300;
    ////////Game Over Buttons///////////////

	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::ToggleExit);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Exit_ST.png", TEXTUREDIR"/Button Textures/Exit_SE.png");
	GameOverButtons.push_back(temp);
	position += 100;
	
	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::SwitchToMain);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Main_ST.png", TEXTUREDIR"/Button Textures/Main_SE.png");
	GameOverButtons.push_back(temp);
	position += 100;
	
	temp = new Button<HUDManager>(Vector3(1280 / 2, position, 0), 40, &HUDManager::ToggleReset_HUD);
	temp->GetSceneNode()->Update(0.0f);
	temp->SetTextures(TEXTUREDIR"/Button Textures/Replay_ST.png", TEXTUREDIR"/Button Textures/Replay_SE.png");
	GameOverButtons.push_back(temp);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	

	//sets intial active list and selected button to main menu buttons
	ActiveList = &StartButtons;
	Selected_Button = ActiveList->end()-1;
	(*Selected_Button)->ToggleSelected();

	//intiliases health bar
	Health_Bar.SetMesh(Mesh::GenerateQuad());
	Health_Bar.SetColour(Vector4(0,255.0f,0,1));
	Health_Bar.SetModelScale(Vector3(Player_Health*5,10,1));
	Health_Bar.SetTransform(Matrix4::Translation(Vector3(1280/2,800-20,0)));
	Health_Bar.Update(0.0f);

	//intiliases energy bar
	Energy_bar.SetMesh(Mesh::GenerateQuad());
	Energy_bar.SetColour(Vector4(1, 0.5, 0, 1));
	Energy_bar.SetModelScale(Vector3(3, player_energy * 2, 3));
	Energy_bar.SetTransform(Matrix4::Translation(Vector3(50, 400, 0))*Matrix4::Rotation(90, Vector3(0, 0, 1)));//1280 / 2
	Energy_bar.Update(0.0f);

	//load high score from file
	LoadHighScore("High_Score.txt");

	//intialise main menu logo
	Logo.SetMesh(Mesh::GenerateQuad());
	Logo.GetMesh()->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"Logo.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS));
	Logo.SetModelScale(Vector3(400, 100, 1));
	Logo.SetTransform(Matrix4::Translation(Vector3(1280 / 2, 800 - 100, 0)));
	Logo.Update(0.0f);
}

void HUDManager::Update(float msec)
{
	//if game state is currently the game running
	if(HUDState == GAME)
	{

		//scale healthbar dependant on player health
		Health_Bar.SetModelScale(Vector3(Player_Health*5,10,1));

		//change bar colour based on player health
		Health_Bar.SetColour(Vector4(0.0f+(1.0f-(Player_Health/100.0f)*1.0f),((Player_Health/100.0f)*1.0f),0,1));

		//scale energybar dependant on player energy
		Energy_bar.SetModelScale(Vector3(player_energy * 2, 20, 1));

		//reduce game time
			GameTime -= (msec/1000.0f);

		//if the player is dead or has ran out of time, its a game over
		if (GameTime <= 0 || Player_Health <= 0)
		{
			GameTime -= (msec / 1000.0f);
			SwitchToGameOver();
		}

		//if xbox controller is not null
		if (playerXbox_controller)
		{
			//toggle debug mode
			if (playerXbox_controller->GetState().Gamepad.wButtons == XINPUT_GAMEPAD_BACK)
			{
			
				ToggleDebugMode();
			}

			//toggle game state from game to paused
			if (playerXbox_controller->GetState().Gamepad.wButtons == XINPUT_GAMEPAD_START)
			{
				if (HUDState != PAUSED)
				{
					 SwitchToPaused();
			}
				else
				{
					 SwitchToGame();
		}
			}
		}

		//toggle debug mode
		if (Window::GetKeyboard()->KeyTriggered(TOGGLE_DEBUG_MODE))
		{
			ToggleDebugMode();
		}

		//toggle game state from game to paused
		if (Window::GetKeyboard()->KeyTriggered(TOGGLE_PAUSE_SCREEN))
		{
			if (HUDState != PAUSED)
			{
				SwitchToPaused();
		}
			else
			{
				SwitchToGame();
	}
		}
	}
	else
	{
		//Navigate menu commands
			if (Window::GetKeyboard()->KeyTriggered(MENU_UP))
			{
				//GameSound::GetInstance()->InsertSound(1,false);
				MoveMenuUp();
			}
			if (Window::GetKeyboard()->KeyTriggered(MENU_DOWN))
			{
				//GameSound::GetInstance()->InsertSound(1, false);
				MoveMenuDown();
			}
			if (Window::GetKeyboard()->KeyTriggered(MENU_ENTER))
			{
				(*Selected_Button)->Execute();
			}

		//navigate menu commands for XBOX controller
		if (playerXbox_controller)
		{

		if (playerXbox_controller->GetState().Gamepad.sThumbLY < -6553)
		{
			MoveMenuUp();
		}

			if (playerXbox_controller->GetState().Gamepad.sThumbLY > 6553)
		{
			MoveMenuDown();
		}

		if (playerXbox_controller->GetState().Gamepad.wButtons == XINPUT_GAMEPAD_A)
		{
			(*Selected_Button)->Execute();
		}
	}
	}
}

vector<SceneNode*> HUDManager::GetDrawList()
{
	//temporary list
	vector<SceneNode*> list;
	
	//if not in main menu
	if (HUDState != MAIN)
	{
		//add health car to list
		list.push_back(&Health_Bar);
		// add energy bar to list
		list.push_back(&Energy_bar);

		//if in pause menu
		if (HUDState == PAUSED)
		{
			//add pause buttons
			for (vector<Button<HUDManager>*>::iterator it = PauseButtons.begin(); it != PauseButtons.end(); it++)
			{
				list.push_back((*it)->GetSceneNode());
			}
		}
		//if in game over screen
		else if (HUDState == GAMEOVER)
		{
			//add gameover buttons
			for (vector<Button<HUDManager>*>::iterator it = GameOverButtons.begin(); it != GameOverButtons.end(); it++)
			{
				list.push_back((*it)->GetSceneNode());
			}
		}
	}
	else 
	{
		//add logo for main menus
		list.push_back(&Logo);

		//add main menu buttons
		for (vector<Button<HUDManager>*>::iterator it = StartButtons.begin(); it != StartButtons.end(); it++)
		{
			list.push_back((*it)->GetSceneNode());
		}
	}

	//return completed list
	return list;
}

void HUDManager::LoadHighScore(char* filename)
{
	//if screatm for file reading
	ifstream myfile;

	//open file
	myfile.open(filename,ios::in|ios::binary|ios::ate);

	//if file was opened
	if(myfile.is_open())
	{
		//copy file contents to buffer
		streampos size = myfile.tellg();
		char* buff = new char[(unsigned int)size];
		myfile.seekg (0, ios::beg);
		myfile.read(buff,size);
		myfile.close();

		//current position in buffer
		int buff_counter = 0;

		//loop through every line and collect high score data
		for(int i = 0 ; i < 10; i++)
		{
			string storage;
			int score;

			while(buff[buff_counter] != ':' && buff_counter < size)
			{
				buff_counter++;
			}
			buff_counter++;

			while(buff[buff_counter] != 'S' && buff_counter < size)
			{
				storage += buff[buff_counter];
				buff_counter++;
			}

			High_Score[i].Name = storage;
			storage.clear();

			while(buff[buff_counter] != ':' && buff_counter < size)
			{
				buff_counter++;
			}
			buff_counter++;

			while(buff[buff_counter] != '\r' && buff_counter < size)
			{
				storage += buff[buff_counter];
				buff_counter++;
			}

			High_Score[i].Score = atoi(storage.c_str());
		}


	}
}

void HUDManager::WriteHighScore(char* filename)
{
	//of stream for file writing
	ofstream outputFile(filename,fstream::out);

	//write high score contents to file
	for(int i = 0; i < 10; i++)
	{
		outputFile << "N:" << High_Score[i].Name;
		outputFile << "S:" << High_Score[i].Score << "\r\n";
	}
}


void HUDManager::AddScore(string name ,int score)
{
	//struct used to store comparing point
	HighScorePoints point;

	//set compare point
	point.Name = name;
	point.Score = score;

	//used to copy contents
	HighScorePoints storage;

	//loop through and compare point with high score. swap when nessassary
	for(int i = 0; i < 10; i++)
	{
		if(High_Score[i].Score < point.Score)
		{
			storage = High_Score[i];
			High_Score[i] = point;
			point = storage;
		}
	}

}


vector<string> HUDManager::GetHighScoreText()
{
	//used to store high score lines
	vector<string> list;

	//if the game is paused or at the main menu
	if (HUDState == PAUSED || HUDState == MAIN)
	{
		//convert high score points then add them to vector 

		list.push_back(string("High Scores"));

		for(int i = 0; i < 10; i++)
		{
			string temp;
			temp += to_string(i+1);

			if(i < 9)
			{
				temp += " ";
			}
			temp += ":";  
			temp += High_Score[i].Name;
			temp += " ";
			temp +=  to_string(High_Score[i].Score);
			list.push_back(temp);
		}
	}

	//return completed list
	return list;
}

void HUDManager::Reset()
{
	//reset HUD values
	Debug_Mode = false;
	Exit = false;
	GameTime = INTIALTIME;
	Score = INTIALSCORE;
	Restart = false;
}

void HUDManager::MoveMenuUp()
{
	//moves iterator up through list, if at end of list then put it back to beginning
	if (Selected_Button != ActiveList->end() - 1)
	{
		(*Selected_Button)->ToggleSelected();
		Selected_Button++;
		(*Selected_Button)->ToggleSelected();
	}
	else
	{
		(*Selected_Button)->ToggleSelected();
		Selected_Button = ActiveList->begin();
		(*Selected_Button)->ToggleSelected();
	}
}

void HUDManager::MoveMenuDown()
{
	//move iterator down list if at start put back to end
	if (Selected_Button != ActiveList->begin())
	{
		(*Selected_Button)->ToggleSelected();
		Selected_Button--;
		(*Selected_Button)->ToggleSelected();
	}
	else
	{
		(*Selected_Button)->ToggleSelected();
		Selected_Button = ActiveList->end() - 1;
		(*Selected_Button)->ToggleSelected();
	}
}
void HUDManager::SwitchToGame()
{
	//changes game state to game
	HUDState = GAME;
	Renderer::GetRenderer().StopExplosionParticle();
	SpringNet::initPos = 2;
}

void HUDManager::SwitchToMain()
{
	//changes HUD state to main and resets the hud.
	//active list becomes main menu buttons
	HUDState = MAIN;
	ToggleReset_HUD();
	(*Selected_Button)->ToggleSelected();
	 ActiveList = &StartButtons;
	 Selected_Button = ActiveList->end() - 1;
	(*Selected_Button)->ToggleSelected();
}

void HUDManager::SwitchToPaused()
{
	//changes HUD state to pauses.
	//active list becomes pause buttons
	HUDState = PAUSED;
	
		(*Selected_Button)->ToggleSelected();
	ActiveList = &PauseButtons;
		Selected_Button = ActiveList->end() - 1;
		(*Selected_Button)->ToggleSelected();
	}

void HUDManager::SwitchToGameOver()
{
	//change HUD to game over and add final score to highscores
	//active list becomes game over buttons

	Renderer::GetRenderer().StartExplosionParticle();
	GameSound::GetInstance()->InsertSound(2, false);

	if (deathDelay)
	{
		deathTime = GameTime;
		deathDelay = false;
	}

	if (deathTime - GameTime > 2.f)
	{
		HUDState = GAMEOVER;
		AddScore("New", Score);

		(*Selected_Button)->ToggleSelected();
		ActiveList = &GameOverButtons;
		Selected_Button = ActiveList->end() - 1;
		(*Selected_Button)->ToggleSelected();

		deathDelay = true;
	}

}